package com.glodon.paas.document.dao.mongo;

import static com.glodon.paas.document.constant.DocumentConstant.*;

import java.util.Arrays;
import java.util.Date;
import java.util.List;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang.StringUtils;

import com.glodon.paas.consts.StringConst;
import com.glodon.paas.document.dao.FileDao;
import com.glodon.paas.document.dao.domain.FileInfoEntity;
import com.glodon.paas.util.DateUtil;
import com.google.code.morphia.query.Query;
import com.google.code.morphia.query.UpdateOperations;

public class FileDaoMongoImpl extends MongoDBDao<FileInfoEntity, String> implements FileDao {

    @Override
    public String insert(FileInfoEntity entity) {
        if (FILE_TYPE_FOLDER.intValue() == entity.getType()) {
            entity.setActiveRevision(1);
        }
        return super.insert(entity);
    }

    @Override
    public void ensureIndexes() {
        super.ensureIndexes();
        mongoDataStore.ensureIndex(this.entityClazz, "ownerId, parentId, name, extension");
        mongoDataStore.ensureIndex(this.entityClazz, "parentId, name, extension");
    }

    // @Override
    // public List<FileInfoEntity> selectByComplex(
    // String ownerId,
    // String parentId,
    // Integer type,
    // Integer deletedStatus,
    // String orderProperty,
    // Integer orderType,
    // Integer startIndex,
    // Integer count) {
    // if(orderType == null){
    // orderType = 1;
    // }
    // // 条件
    // Query<FileInfoEntity> q = this.createQuery();
    // if(ownerId!=null){
    // q.filter("ownerId", ownerId);
    // }
    // if(parentId!=null){
    // q.filter("parentId", parentId);
    // }
    // if(type!=null){
    // q.filter("type", type);
    // }
    // if(deletedStatus!=null){
    // q.filter("deletedStatus", deletedStatus);
    // }
    // else{
    // q.filter("deletedStatus <>", FILE_STATUS_DELETED);
    // }
    // // if(available != null ){
    // // if(available){
    // // q.filter("activeRevision >", 0);
    // // }else{
    // // q.filter("activeRevision =", 0);
    // // }
    // // }
    //
    // // 排序
    // q.order("type");
    // if(orderProperty != null){
    // if(orderType.intValue() == DatabaseConst.ORDER_BY_DESC_INT){
    // q.order("-"+orderProperty);
    // }else{
    // q.order(orderProperty);
    // }
    // }
    // // 分页
    // q.offset(startIndex).limit(count);
    // return q.asList();
    // }

    // @Override
    // public String getFileId(String ownerId, String parentId, String path, Integer[] status) {
    // FileInfoEntity f = StringUtils.isNotEmpty(parentId) ? this.get(parentId) : null;
    // String[] names = StringUtils.split(path, StringConst.SEPARATOR_SLASH);
    // for(String name : names) {
    // String baseName = FilenameUtils.getBaseName(name);
    // String extension = FilenameUtils.getExtension(name);
    // Query<FileInfoEntity> query = createQuery().retrievedFields(true, "id").filter("ownerId", ownerId)
    // .filter("parentId", (f != null) ? f.getId() : "")
    // .filter("name", baseName)
    // .filter("extension", extension);
    // if(status != null){
    // query.field("deletedStatus").in(Arrays.asList(status));
    // }
    // f = query.get();
    // if (f == null) {
    // return null;
    // }
    // }
    // return f.getId();
    // }
    //
    // @Override
    // public FileInfoEntity getRootDoc(String userId, String fullName) {
    // String name = FilenameUtils.getBaseName(fullName);
    // String extension = FilenameUtils.getExtension(fullName).toLowerCase();
    // Query<FileInfoEntity> q = this.createQuery().filter("ownerId", userId)
    // .filter("parentId =", "")
    // .filter("name", name)
    // .filter("extension", extension)
    // .filter("deletedStatus", FILE_STATUS_NORMAL)
    // .filter("type =", FILE_TYPE_FILE);
    // return q.get();
    // }
    //
    // @Override
    // public FileInfoEntity getDocByParentName(String parentId, String fullName) {
    // String name = FilenameUtils.getBaseName(fullName);
    // String extension = FilenameUtils.getExtension(fullName).toLowerCase();
    // Query<FileInfoEntity> q = this.createQuery().filter("parentId", parentId)
    // .filter("name", name)
    // .filter("extension", extension)
    // .filter("deletedStatus", FILE_STATUS_NORMAL)
    // .filter("type =", FILE_TYPE_FILE);
    // return q.get();
    // }
    //
    // @Override
    // public FileInfoEntity getRootFolder(String userId, String folderName) {
    // Query<FileInfoEntity> q = this.createQuery().filter("ownerId", userId)
    // .filter("parentId =", "")
    // .filter("name", folderName)
    // .filter("deletedStatus", FILE_STATUS_NORMAL)
    // .filter("type =", FILE_TYPE_FOLDER);
    // return q.get();
    // }
    //
    // @Override
    // public FileInfoEntity getFolderByParentName(String parentId, String folderName) {
    // Query<FileInfoEntity> q = this.createQuery().filter("parentId", parentId)
    // .filter("name", folderName)
    // .filter("deletedStatus", FILE_STATUS_NORMAL)
    // .filter("type =", FILE_TYPE_FOLDER);
    // return q.get();
    // }
    //
    // @Override
    // public List<FileInfoEntity> getRootFiles(String userId) {
    // Query<FileInfoEntity> q = this.createQuery().filter("ownerId =", userId)
    // .filter("parentId =", "")
    // .filter("deletedStatus", FILE_STATUS_NORMAL)
    // .order("-type");
    // return q.asList();
    // }
    //
    // @Override
    // public List<FileInfoEntity> getSubFiles(String fileId) {
    // Query<FileInfoEntity> q = this.createQuery().filter("parentId =", fileId)
    // .filter("deletedStatus", FILE_STATUS_NORMAL)
    // .order("-type");
    // return q.asList();
    // }
    //
    // @Override
    // public List<FileInfoEntity> getAllSubFiles(String fileId) {
    // Query<FileInfoEntity> q = this.createQuery().filter("parentId =", fileId)
    // .order("type");
    // return q.asList();
    // }

    @Override
    public void updateStatus(String fileId, Integer deleteType) {
        Query<FileInfoEntity> query = createQuery().filter("id", fileId);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("deletedStatus", deleteType);
        updateFirst(query, update);
    }

    @Override
    public void delFile(String fileId) {
        this.delete(fileId);
    }

    @Override
    public void cleanByOwnerId(String ownerId) {
        Query<FileInfoEntity> query = createQuery().filter("ownerId =", ownerId);
        super.deleteByQuery(query);

    }

    // TODO maybe should sum file size from revision not file,
    @Override
    public long getUsedSpace(String userId) {
        long space = 0;
        Query<FileInfoEntity> q = this.createQuery().filter("ownerId =", userId).filter("deletedStatus <>",
                                                                                        FILE_STATUS_DELETED);
        List<FileInfoEntity> files = q.asList();
        if (files != null) {
            for (FileInfoEntity file : files) {
                space += file.getSize();
            }
        }
        return space;
    }

    @Override
    public void updateFileName(String fileId, String newName, String updator) {
        Query<FileInfoEntity> query = createQuery().filter("id", fileId).filter("deletedStatus <>", FILE_STATUS_DELETED);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("name", newName).set("updateTime",
                                                                                                         DateUtil.getNow());
        this.updateFirst(query, update);
    }

    @Override
    public void updateShareType(String fileId, Integer type) {
        Query<FileInfoEntity> query = createQuery().filter("id", fileId);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("shareType", type);
        updateFirst(query, update);
    }

    @Override
    public String getParentId(String fileId) {
        Query<FileInfoEntity> q = this.createQuery().filter("id =", fileId).filter("deletedStatus <>",
                                                                                   FILE_STATUS_DELETED).retrievedFields(true,
                                                                                                                        "parentId");
        FileInfoEntity f = q.get();
        if (f != null) {
            return q.get().getParentId();
        } else {
            return null;
        }
    }

    // @Override
    // public FileInfoEntity getDeletedFile(String userId, String fileId) {
    // Query<FileInfoEntity> q = this.createQuery().filter("id =", fileId).filter("ownerId =",
    // userId).filter("deletedStatus <>", FILE_STATUS_NORMAL);
    //
    // return q.get();
    // }

    // @Override
    // public void restore(String fileId) {
    // Query<FileInfoEntity> query = createQuery().filter("id", fileId);
    // UpdateOperations<FileInfoEntity> update = this.createUpdateOperations()
    // .set("deletedStatus", FILE_STATUS_NORMAL)
    // .set("updateTime", DateUtil.getNow());
    // updateFirst(query, update);
    // }

    @Override
    public void updateSizeNumCount(String fileId, long size, int num, int count, Date updateTime) {
        Query<FileInfoEntity> query = createQuery().filter("id", fileId).filter("deletedStatus <>", FILE_STATUS_DELETED);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("activeRevision", num).set("size",
                                                                                                               size).set("count",
                                                                                                                         count).set("updateTime",
                                                                                                                                    updateTime);
        updateFirst(query, update);
    }

    // @Override
    // public String getFileOwner(String fileId) {
    // Query<FileInfoEntity> q = this.createQuery().filter("id =", fileId).filter("deletedStatus <>",
    // FILE_STATUS_DELETED).retrievedFields(true, "ownerId");
    // FileInfoEntity file = q.get();
    // if(file != null){
    // return file.getOwnerId();
    // }
    // else{
    // return null;
    // }
    // }

    @Override
    public void refreshCount(String fileId) {
        Query<FileInfoEntity> query = createQuery().filter("parentId", fileId).filter("deletedStatus =",
                                                                                      FILE_STATUS_NORMAL);
        Query<FileInfoEntity> q = createQuery().filter("id", fileId);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("count", (int) count(query));
        updateFirst(q, update);
    }

    // @Override
    // public void decreaseCount(String fileId) {
    // Query<FileInfoEntity> query = createQuery().filter("id", fileId).filter("deletedStatus <>", FILE_STATUS_DELETED);
    // UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().dec("count");
    // updateFirst(query, update);
    // }

    // @Override
    // public int count(String ownerId, String parentId, Integer type, Integer deletedStatus) {
    // Query<FileInfoEntity> q = this.createQuery();
    //
    // if(StringUtils.isBlank(parentId)){
    // q.filter("ownerId =", ownerId);
    // }
    // if(parentId != null){
    // q.filter("parentId =", parentId);
    // }
    // if(type != null){
    // q.filter("type =", type);
    // }
    // if(deletedStatus != null){
    // q.filter("deletedStatus =", deletedStatus);
    // }
    // return (int)q.countAll();
    // }

    // @Override
    // public int updateCount(String fileId, int count) {
    // Query<FileInfoEntity> query = createQuery().filter("id", fileId);
    // UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("count", count);
    // return this.updateFirst(query, update);
    // }

    @Override
    public int updateDataBagId(String fileId, String dataBagId) {
        Query<FileInfoEntity> query = createQuery().filter("id", fileId).filter("deletedStatus <>", FILE_STATUS_DELETED);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("dataBagId", dataBagId);
        return this.updateFirst(query, update);
    }

    @Override
    public FileInfoEntity getFile(String fileId, Integer[] status, Integer[] types) {
        Query<FileInfoEntity> q = this.createQuery().filter("id", fileId).filter("deletedStatus <>",
                                                                                 FILE_STATUS_DELETED);
        if (status != null) {
            q.field("deletedStatus").in(Arrays.asList(status));
        }
        if (types != null) {
            q.field("type").in(Arrays.asList(types));
        }
        return q.get();
    }

    @Override
    public String getFileId(String parentId, String path, Integer[] status, Integer[] types) {
        FileInfoEntity f = null;
        String[] names = StringUtils.split(path, StringConst.SEPARATOR_SLASH);
        List<FileInfoEntity> files;
        for (String name : names) {
            String baseName = FilenameUtils.getBaseName(name);
            String extension = FilenameUtils.getExtension(name);
            Query<FileInfoEntity> query = createQuery().retrievedFields(true, "id").filter("parentId", parentId).filter("name",
                                                                                                                        baseName).filter("extension",
                                                                                                                                         extension);
            if (status != null) {
                query.field("deletedStatus").in(Arrays.asList(status));
            } else {
                query.filter("deletedStatus <>", FILE_STATUS_DELETED);
            }
            if (types != null) {
                query.field("type").in(Arrays.asList(types));
            }
            files = query.asList();
            if (files.size() == 0) {
                return null;
            } else if (files.size() > 1) {
                logger.warn("too many sub files in file[" + parentId + "]");
            }
            f = files.get(0);
            parentId = f.getId();
        }
        return f.getId();
    }

    @Override
    public List<FileInfoEntity> getFiles(String parentId, String name, Integer[] status, Integer[] types) {
        Query<FileInfoEntity> q = this.createQuery().filter("parentId", parentId);
        if (StringUtils.isNotEmpty(name)) {
            String baseName = FilenameUtils.getBaseName(name);
            String extension = FilenameUtils.getExtension(name);
            q.filter("name", baseName).filter("extension", extension);
        }
        if (status != null) {
            q.field("deletedStatus").in(Arrays.asList(status));
        } else {
            q.filter("deletedStatus <>", FILE_STATUS_DELETED);
        }
        if (types != null) {
            q.field("type").in(Arrays.asList(types));
        }
        return q.asList();
    }

    @Override
    public List<FileInfoEntity> getExpiredFiles(String ownerId, int nDays, int limited) {
        Date delDay = DateUtil.getDate(DateUtil.intDateSub(DateUtil.getIntToday(), nDays));
        Query<FileInfoEntity> q = this.createQuery();
        if (StringUtils.isNotEmpty(ownerId)) {
            q.filter("ownerId =", ownerId);
        }
        q.filter("deletedStatus", FILE_STATUS_DELETED).filter("updateTime <", delDay).retrievedFields(true, "id").retrievedFields(true,
                                                                                                                                  "type").order("updateTime").limit(limited);
        return q.asList();
    }

    @Override
    public int updateParent(String fileId, String parentId) {
        Query<FileInfoEntity> query = createQuery().filter("id", fileId).filter("deletedStatus <>", FILE_STATUS_DELETED);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("parentId", parentId);
        return this.updateFirst(query, update);
    }

    @Override
    public void updateCount(String fileId, int count) {
        Query<FileInfoEntity> query = createQuery().filter("id", fileId).filter("deletedStatus <>", FILE_STATUS_DELETED);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("count", count);
        this.updateFirst(query, update);
    }

    @Override
    public void updateUpdator(String fileId, String userId) {
        Query<FileInfoEntity> query = createQuery().filter("id", fileId).filter("deletedStatus <>", FILE_STATUS_DELETED);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("updator", userId);
        this.updateFirst(query, update);
    }

    @Override
    public void updateLock(String fileId, String lockId) {
        Query<FileInfoEntity> query = createQuery().filter("id", fileId).filter("deletedStatus <>", FILE_STATUS_DELETED);
        UpdateOperations<FileInfoEntity> update = this.createUpdateOperations().set("lockId", lockId);
        this.updateFirst(query, update);
    }

    @Override
    public List<FileInfoEntity> getDeletedFiles(String ownerId) {
        Query<FileInfoEntity> query = createQuery().filter("ownerId", ownerId).filter("deletedStatus =",
                                                                                      FILE_STATUS_RECYCLE);
        return query.asList();
    }

    /* (non-Javadoc)
     * @see com.glodon.paas.document.dao.FileDao#getFileWithFolderCount(java.lang.String)
     */
    @Override
    public FileInfoEntity getFileWithFolderCount(String fileId) {
        // TODO Auto-generated method stub
        return null;
    }
}
